home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / DistUpgrade / DistUpgradeQuirks.py < prev    next >
Encoding:
Python Source  |  2009-04-27  |  32.9 KB  |  713 lines

  1. # DistUpgradeQuirks.py 
  2. #  
  3. #  Copyright (c) 2004-2008 Canonical
  4. #  
  5. #  Author: Michael Vogt <michael.vogt@ubuntu.com>
  6. #  This program is free software; you can redistribute it and/or 
  7. #  modify it under the terms of the GNU General Public License as 
  8. #  published by the Free Software Foundation; either version 2 of the
  9. #  License, or (at your option) any later version.
  10. #  This program is distributed in the hope that it will be useful,
  11. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. #  GNU General Public License for more details.
  14. #  You should have received a copy of the GNU General Public License
  15. #  along with this program; if not, write to the Free Software
  16. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  17. #  USA
  18.  
  19. import glob
  20. import logging
  21. import os
  22. import os.path
  23. import re
  24. import shutil
  25. import string
  26. import sys
  27. import subprocess
  28. from subprocess import PIPE, Popen, call
  29. from hashlib import md5
  30.  
  31. from DistUpgradeGettext import gettext as _
  32. from DistUpgradeGettext import ngettext
  33. import gettext
  34.  
  35. from computerjanitor.plugin import PluginManager
  36.  
  37. class DistUpgradeQuirks(object):
  38.     """
  39.     This class collects the various quirks handlers that can
  40.     be hooked into to fix/work around issues that the individual
  41.     releases have
  42.     """
  43.     
  44.     def __init__(self, controller, config):
  45.         self.controller = controller
  46.         self._view = controller._view
  47.         self.config = config
  48.         self.uname = Popen(["uname","-r"],stdout=PIPE).communicate()[0].strip()
  49.         self.plugin_manager = PluginManager(self.controller, ["./plugins"])
  50.  
  51.     # the quirk function have the name:
  52.     #  $Name (e.g. PostUpgrade)
  53.     #  $todist$Name (e.g. intrepidPostUpgrade)
  54.     #  $from_$fromdist$Name (e.g. from_dapperPostUpgrade)
  55.     def run(self, quirksName):
  56.         """
  57.         Run the specific quirks handler, the follow handlers are supported:
  58.         - PostInitialUpdate: run *before* the sources.list is rewritten but
  59.                              after a initial apt-get update
  60.         - PostDistUpgradeCache: run *after* the dist-upgrade was calculated
  61.                                 in the cache
  62.         - StartUpgrade: before the first package gets installed (but the
  63.                         download is finished)
  64.         - PostUpgrade: run *after* the upgrade is finished successfully and 
  65.                        packages got installed
  66.         - PostCleanup: run *after* the cleanup (orphaned etc) is finished
  67.         """
  68.         # first check for matching plugins
  69.         for condition in [
  70.             quirksName,
  71.             "%s%s" %  (self.config.get("Sources","To"), quirksName),
  72.             "from_%s%s" % (self.config.get("Sources","From"), quirksName)
  73.             ]:
  74.             for plugin in self.plugin_manager.get_plugins(condition):
  75.                 logging.debug("running quirks plugin %s" % plugin)
  76.                 plugin.do_cleanup_cruft()
  77.         
  78.         # run the handler that is common to all dists
  79.         funcname = "%s" % quirksName
  80.         func = getattr(self, funcname, None)
  81.         if func is not None:
  82.             logging.debug("quirks: running %s" % funcname)
  83.             func()
  84.  
  85.         # run the quirksHandler to-dist
  86.         funcname = "%s%s" % (self.config.get("Sources","To"), quirksName)
  87.         func = getattr(self, funcname, None)
  88.         if func is not None:
  89.             logging.debug("quirks: running %s" % funcname)
  90.             func()
  91.  
  92.         # now run the quirksHandler from_${FROM-DIST}Quirks
  93.         funcname = "from_%s%s" % (self.config.get("Sources","From"), quirksName)
  94.         func = getattr(self, funcname, None)
  95.         if func is not None:
  96.             logging.debug("quirks: running %s" % funcname)
  97.             func()
  98.  
  99.     # individual quirks handler when the dpkg run is finished ---------
  100.     def PostCleanup(self):
  101.         " run after cleanup " 
  102.         logging.debug("running Quirks.PostCleanup")
  103.  
  104.     def from_dapperPostUpgrade(self):
  105.         " this works around quirks for dapper->hardy upgrades "
  106.         logging.debug("running Controller.from_dapperQuirks handler")
  107.         self._rewriteFstab()
  108.         self._checkAdminGroup()
  109.         
  110.     def intrepidPostUpgrade(self):
  111.         " this applies rules for the hardy->intrepid upgrade "
  112.     logging.debug("running Controller.intrepidQuirks handler")
  113.         self._addRelatimeToFstab()
  114.  
  115.     def gutsyPostUpgrade(self):
  116.         """ this function works around quirks in the feisty->gutsy upgrade """
  117.         logging.debug("running Controller.gutsyQuirks handler")
  118.  
  119.     def feistyPostUpgrade(self):
  120.         """ this function works around quirks in the edgy->feisty upgrade """
  121.         logging.debug("running Controller.feistyQuirks handler")
  122.         self._rewriteFstab()
  123.         self._checkAdminGroup()
  124.  
  125.     # quirks when run when the initial apt-get update was run -------
  126.  
  127.     # fglrx is broken in intrepid (no support for xserver 1.5)
  128.     def jauntyPostInitialUpdate(self):
  129.         " quirks that are run before the upgrade to jaunty "
  130.         logging.debug("running %s" %  sys._getframe().f_code.co_name
  131. )
  132.         # this is to deal with the fact that support for some of the cards
  133.         # that fglrx used to support got dropped
  134.         if (self._checkVideoDriver("fglrx") and 
  135.             not self._supportInModaliases("fglrx")):
  136.              res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
  137.                                          "effects, and performance in games "
  138.                                          "and other graphically intensive "
  139.                                          "programs."),
  140.                                        _("This computer is currently using "
  141.                                          "the AMD 'fglrx' graphics driver. "
  142.                                          "No version of this driver is "
  143.                                          "available that works with your "
  144.                                          "hardware in Ubuntu "
  145.                                          "9.04.\n\nDo you want to continue?"))
  146.              if res == False:
  147.                  self.controller.abort()
  148.              # if the user wants to continue we remove the fglrx driver
  149.              # here because its no use (no support for this card)
  150.              logging.debug("remove xorg-driver-fglrx,xorg-driver-fglrx-envy,fglrx-kernel-source")
  151.              l=self.controller.config.getlist("Distro","PostUpgradePurge")
  152.              l.append("xorg-driver-fglrx")
  153.              l.append("xorg-driver-fglrx-envy")
  154.              l.append("fglrx-kernel-source")
  155.              l.append("fglrx-amdcccle")
  156.              l.append("xorg-driver-fglrx-dev")
  157.              l.append("libamdxvba1")
  158.              self.controller.config.set("Distro","PostUpgradePurge",",".join(l))
  159.  
  160.     # quirks when the cache upgrade calculation is finished
  161.     def from_dapperPostDistUpgradeCache(self):
  162.         self.hardyPostDistUpgradeCache()
  163.         self.gutsyPostDistUpgradeCache()
  164.         self.feistyPostDistUpgradeCache()
  165.         self.edgyPostDistUpgradeCache()
  166.  
  167.     def jauntyPostDistUpgradeCache(self):
  168.         """ 
  169.         this function works around quirks in the 
  170.         intrepid->jaunty upgrade calculation
  171.         """
  172.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  173.         # bug 332328 - make sure pidgin-libnotify is upgraded
  174.         for pkg in ["pidgin-libnotify"]:
  175.             if (self.controller.cache.has_key(pkg) and
  176.                 self.controller.cache[pkg].isInstalled and
  177.                 not self.controller.cache[pkg].markedUpgrade):
  178.                 logging.debug("forcing '%s' upgrade" % pkg)
  179.                 self.controller.cache[pkg].markUpgrade()
  180.         # deal with kipi/gwenview/kphotoalbum
  181.         for pkg in ["gwenview","digikam"]:
  182.             if (self.controller.cache.has_key(pkg) and
  183.                 self.controller.cache[pkg].isInstalled and
  184.                 not self.controller.cache[pkg].markedUpgrade):
  185.                 logging.debug("forcing libkipi '%s' upgrade" % pkg)
  186.                 if self.controller.cache.has_key("libkipi0"):
  187.                     logging.debug("removing  libkipi0)")
  188.                     self.controller.cache["libkipi0"].markDelete()
  189.                 self.controller.cache[pkg].markUpgrade()
  190.         
  191.     def intrepidPostDistUpgradeCache(self):
  192.         """ 
  193.         this function works around quirks in the 
  194.         hardy->intrepid upgrade 
  195.         """
  196.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  197.         # check if a key depends of kubuntu-kde4-desktop is installed
  198.         # and transition in this case as well
  199.         deps_found = False
  200.         if self.config.getlist(frompkg,"KeyDependencies"):
  201.             deps_found = True
  202.             for pkg in self.config.getlist(frompkg,"KeyDependencies"):
  203.                 deps_found &= (self.controller.cache.has_key(pkg) and
  204.                                self.controller.cache[pkg].isInstalled)
  205.         if deps_found:
  206.             logging.debug("transitioning %s to %s (via key depends)" % (frompkg, topkg))
  207.             self.controller.cache[topkg].markInstall()
  208.         # now check for nvidia and show a warning if needed
  209.         cache = self.controller.cache
  210.         for pkgname in ["nvidia-glx-71","nvidia-glx-96"]:
  211.             if (cache.has_key(pkgname) and 
  212.                 cache[pkgname].markedInstall and
  213.                 self._checkVideoDriver("nvidia")):
  214.                 logging.debug("found %s video driver" % pkgname)
  215.                 res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
  216.                                         "effects, and performance in games "
  217.                                         "and other graphically intensive "
  218.                                         "programs."),
  219.                                       _("This computer is currently using "
  220.                                         "the NVIDIA 'nvidia' "
  221.                                         "graphics driver. "
  222.                                         "No version of this driver is "
  223.                                         "available that works with your "
  224.                                         "video card in Ubuntu "
  225.                                         "8.10.\n\nDo you want to continue?"))
  226.                 if res == False:
  227.                     self.controller.abort()
  228.                 # if the user continue, do not install the broken driver
  229.                 # so that we can transiton him to the free "nv" one after
  230.                 # the upgrade
  231.                 self.controller.cache[pkgname].markKeep()
  232.         # check if we have sse
  233.         for pkgname in ["nvidia-glx-173","nvidia-glx-177"]:
  234.             if (cache.has_key(pkgname) and 
  235.                 cache[pkgname].markedInstall and
  236.                 self._checkVideoDriver("nvidia")):
  237.                 logging.debug("found %s video driver" % pkgname)
  238.                 if not self._cpuHasSSESupport():
  239.                     logging.warning("nvidia driver that needs SSE but cpu has no SSE support")
  240.                     res = self._view.askYesNoQuestion(_("Upgrading may reduce desktop "
  241.                                         "effects, and performance in games "
  242.                                         "and other graphically intensive "
  243.                                         "programs."),
  244.                                       _("This computer is currently using "
  245.                                         "the NVIDIA 'nvidia' "
  246.                                         "graphics driver. "
  247.                                         "No version of this driver is "
  248.                                         "available that works with your "
  249.                                         "video card in Ubuntu "
  250.                                         "8.10.\n\nDo you want to continue?"))
  251.                     if res == False:
  252.                         self.controller.abort()
  253.                     # if the user continue, do not install the broken driver
  254.                     # so that we can transiton him to the free "nv" one after
  255.                     # the upgrade
  256.                     self.controller.cache[pkgname].markKeep()
  257.         # kdelibs4-dev is unhappy (#279621)
  258.         fromp = "kdelibs4-dev"
  259.         to = "kdelibs5-dev"
  260.         if (self.controller.cache.has_key(fromp) and 
  261.             self.controller.cache[fromp].isInstalled and
  262.             self.controller.cache.has_key(to)):
  263.             self.controller.cache.markInstall(to, "kdelibs4-dev -> kdelibs5-dev transition")
  264.  
  265.     def hardyPostDistUpgradeCache(self):
  266.         """ 
  267.         this function works around quirks in the 
  268.         {dapper,gutsy}->hardy upgrade 
  269.         """
  270.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  271.         # deal with gnome-translator and help apt with the breaks
  272.         if (self.controller.cache.has_key("nautilus") and
  273.             self.controller.cache["nautilus"].isInstalled and
  274.             not self.controller.cache["nautilus"].markedUpgrade):
  275.             # uninstallable and gutsy apt is unhappy about this
  276.             # breaks because it wants to upgrade it and gives up
  277.             # if it can't
  278.             for broken in ("link-monitor-applet"):
  279.                 if self.controller.cache.has_key(broken) and self.controller.cache[broken].isInstalled:
  280.                     self.controller.cache[broken].markDelete()
  281.             self.controller.cache["nautilus"].markInstall()
  282.         # evms gives problems, remove it if it is not in use
  283.         self._checkAndRemoveEvms()
  284.         # give the language-support-* packages a extra kick
  285.         # (if we have network, otherwise this will not work)
  286.         if self.config.get("Options","withNetwork") == "True":
  287.             for pkg in self.controller.cache:
  288.                 if (pkg.name.startswith("language-support-") and
  289.                     pkg.isInstalled and
  290.                     not pkg.markedUpgrade):
  291.                     self.controller.cache.markInstall(pkg.name,"extra language-support- kick")
  292.  
  293.     def gutsyPostDistUpgradeCache(self):
  294.         """ this function works around quirks in the feisty->gutsy upgrade """
  295.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  296.         # lowlatency kernel flavour vanished from feisty->gutsy
  297.         try:
  298.             (version, build, flavour) = self.uname.split("-")
  299.             if (flavour == 'lowlatency' or 
  300.                 flavour == '686' or
  301.                 flavour == 'k7'):
  302.                 kernel = "linux-image-generic"
  303.                 if not (self.controller.cache[kernel].isInstalled or self.controller.cache[kernel].markedInstall):
  304.                     logging.debug("Selecting new kernel '%s'" % kernel)
  305.                     self.controller.cache[kernel].markInstall()
  306.         except Exception, e:
  307.             logging.warning("problem while transitioning lowlatency kernel (%s)" % e)
  308.         # fix feisty->gutsy utils-linux -> nfs-common transition (LP: #141559)
  309.         try:
  310.             for line in map(string.strip, open("/proc/mounts")):
  311.                 if line == '' or line.startswith("#"):
  312.                     continue
  313.                 try:
  314.                     (device, mount_point, fstype, options, a, b) = line.split()
  315.                 except Exception, e:
  316.                     logging.error("can't parse line '%s'" % line)
  317.                     continue
  318.                 if "nfs" in fstype:
  319.                     logging.debug("found nfs mount in line '%s', marking nfs-common for install " % line)
  320.                     self.controller.cache["nfs-common"].markInstall()
  321.                     break
  322.         except Exception, e:
  323.             logging.warning("problem while transitioning util-linux -> nfs-common (%s)" % e)
  324.  
  325.     def feistyPostDistUpgradeCache(self):
  326.         """ this function works around quirks in the edgy->feisty upgrade """
  327.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  328.         # ndiswrapper changed again *sigh*
  329.         for (fr, to) in [("ndiswrapper-utils-1.8","ndiswrapper-utils-1.9")]:
  330.             if self.controller.cache.has_key(fr) and self.controller.cache.has_key(to):
  331.                 if self.controller.cache[fr].isInstalled and not self.controller.cache[to].markedInstall:
  332.                     try:
  333.                         self.controller.cache.markInstall(to,"%s->%s quirk upgrade rule" % (fr, to))
  334.                     except SystemError, e:
  335.                         logging.warning("Failed to apply %s->%s install (%s)" % (fr, to, e))
  336.             
  337.  
  338.     def edgyPostDistUpgradeCache(self):
  339.         """ this function works around quirks in the dapper->edgy upgrade """
  340.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  341.         for pkg in self.controller.cache:
  342.             # deal with the python2.4-$foo -> python-$foo transition
  343.             if (pkg.name.startswith("python2.4-") and
  344.                 pkg.isInstalled and
  345.                 not pkg.markedUpgrade):
  346.                 basepkg = "python-"+pkg.name[len("python2.4-"):]
  347.                 if (self.controller.cache.has_key(basepkg) and 
  348.                     self.controller.cache[basepkg].candidateDownloadable and
  349.                     not self.controller.cache[basepkg].markedInstall):
  350.                     try:
  351.                         self.controller.cache.markInstall(basepkg,
  352.                                          "python2.4->python upgrade rule")
  353.                     except SystemError, e:
  354.                         logging.debug("Failed to apply python2.4->python install: %s (%s)" % (basepkg, e))
  355.             # xserver-xorg-input-$foo gives us trouble during the upgrade too
  356.             if (pkg.name.startswith("xserver-xorg-input-") and
  357.                 pkg.isInstalled and
  358.                 not pkg.markedUpgrade):
  359.                 try:
  360.                     self.controller.cache.markInstall(pkg.name, "xserver-xorg-input fixup rule")
  361.                 except SystemError, e:
  362.                     logging.debug("Failed to apply fixup: %s (%s)" % (pkg.name, e))
  363.             
  364.         # deal with held-backs that are unneeded
  365.         for pkgname in ["hpijs", "bzr", "tomboy"]:
  366.             if (self.controller.cache.has_key(pkgname) and self.controller.cache[pkgname].isInstalled and
  367.                 self.controller.cache[pkgname].isUpgradable and not self.controller.cache[pkgname].markedUpgrade):
  368.                 try:
  369.                     self.controller.cache.markInstall(pkgname,"%s quirk upgrade rule" % pkgname)
  370.                 except SystemError, e:
  371.                     logging.debug("Failed to apply %s install (%s)" % (pkgname,e))
  372.         # libgl1-mesa-dri from xgl.compiz.info (and friends) breaks the
  373.     # upgrade, work around this here by downgrading the package
  374.         if self.controller.cache.has_key("libgl1-mesa-dri"):
  375.             pkg = self.controller.cache["libgl1-mesa-dri"]
  376.             # the version from the compiz repo has a "6.5.1+cvs20060824" ver
  377.             if (pkg.candidateVersion == pkg.installedVersion and
  378.                 "+cvs2006" in pkg.candidateVersion):
  379.                 for ver in pkg._pkg.VersionList:
  380.                     # the "official" edgy version has "6.5.1~20060817-0ubuntu3"
  381.                     if "~2006" in ver.VerStr:
  382.             # ensure that it is from a trusted repo
  383.             for (VerFileIter, index) in ver.FileList:
  384.                 indexfile = self.controller.cache._list.FindIndex(VerFileIter)
  385.                 if indexfile and indexfile.IsTrusted:
  386.                     logging.info("Forcing downgrade of libgl1-mesa-dri for xgl.compz.info installs")
  387.                                 self.controller.cache._depcache.SetCandidateVer(pkg._pkg, ver)
  388.                     break
  389.                                     
  390.         # deal with general if $foo is installed, install $bar
  391.         for (fr, to) in [("xserver-xorg-driver-all","xserver-xorg-video-all")]:
  392.             if self.controller.cache.has_key(fr) and self.controller.cache.has_key(to):
  393.                 if self.controller.cache[fr].isInstalled and not self.controller.cache[to].markedInstall:
  394.                     try:
  395.                         self.controller.cache.markInstall(to,"%s->%s quirk upgrade rule" % (fr, to))
  396.                     except SystemError, e:
  397.                         logging.debug("Failed to apply %s->%s install (%s)" % (fr, to, e))
  398.                     
  399.     def dapperPostDistUpgradeCache(self):
  400.         """ this function works around quirks in the breezy->dapper upgrade """
  401.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  402.         if (self.controller.cache.has_key("nvidia-glx") and self.controller.cache["nvidia-glx"].isInstalled and
  403.             self.controller.cache.has_key("nvidia-settings") and self.controller.cache["nvidia-settings"].isInstalled):
  404.             logging.debug("nvidia-settings and nvidia-glx is installed")
  405.             self.controller.cache.markRemove("nvidia-settings")
  406.             self.controller.cache.markInstall("nvidia-glx")
  407.  
  408.     def from_hardyPostDistUpgradeCache(self):
  409.         """ this function works around quirks in upgrades from hardy """
  410.         logging.debug("running %s" %  sys._getframe().f_code.co_name)
  411.         # evms got removed after hardy, warn and abort
  412.         if self._usesEvmsInMounts():
  413.             logging.error("evms in use in /etc/fstab")
  414.             self._view.error(_("evms in use"),
  415.                              _("Your system uses the 'evms' volume manager "
  416.                                "in /proc/mounts. "
  417.                                "The 'evms' software is no longer supported, "
  418.                                "please switch it off and run the upgrade "
  419.                                "again when this is done."))
  420.             self.controller.abort()
  421.  
  422.     # run right before the first packages get installed
  423.     def StartUpgrade(self):
  424.         self._applyPatches()
  425.         self._removeOldApportCrashes()
  426.         self._removeBadMaintainerScripts()
  427.     def jauntyStartUpgrade(self):
  428.         self._createPycentralPkgRemove()
  429.         # hal/NM triggers problem, if the old (intrepid) hal gets
  430.         # triggered for a restart this causes NM to drop all connections
  431.         # because (old) hal thinks it has no devices anymore (LP: #327053)
  432.         ap = "/var/lib/dpkg/info/hal.postinst"
  433.         if os.path.exists(ap):
  434.             # intrepid md5 of hal.postinst (jaunty one is different)
  435.             # md5 jaunty 22c146857d751181cfe299a171fc11c9
  436.             md5sum = "146145275900af343d990a4dea968d7c"
  437.             if md5(open(ap).read()).hexdigest() == md5sum:
  438.                 logging.debug("removing bad script '%s'" % ap)
  439.                 os.unlink(ap)
  440.  
  441.  
  442.     # helpers
  443.     def _removeBadMaintainerScripts(self):
  444.         " remove bad/broken maintainer scripts (last resort) "
  445.         # apache: workaround #95325 (edgy->feisty)
  446.         # pango-libthai #103384 (edgy->feisty)
  447.         bad_scripts = ["/var/lib/dpkg/info/apache2-common.prerm",
  448.                        "/var/lib/dpkg/info/pango-libthai.postrm",
  449.                        ]
  450.         for ap in bad_scripts:
  451.             if os.path.exists(ap):
  452.                 logging.debug("removing bad script '%s'" % ap)
  453.                 os.unlink(ap)
  454.  
  455.     def _createPycentralPkgRemove(self):
  456.         """
  457.         intrepid->jaunty, create /var/lib/pycentral/pkgremove flag file
  458.         to help python-central so that it removes all preinst links
  459.         on upgrade
  460.         """
  461.         logging.debug("adding pkgremove file")
  462.         if not os.path.exists("/var/lib/pycentral/"):
  463.             os.makedirs("/var/lib/pycentral")
  464.         open("/var/lib/pycentral/pkgremove","w")
  465.  
  466.     def _removeOldApportCrashes(self):
  467.         " remove old apport crash files "
  468.         try:
  469.             for f in glob.glob("/var/crash/*.crash"):
  470.                 logging.debug("removing old crash file '%s'" % f)
  471.                 os.unlink(f)
  472.         except Exception, e:
  473.             logging.warning("error during unlink of old crash files (%s)" % e)
  474.  
  475.     def _cpuHasSSESupport(self, cpuinfo="/proc/cpuinfo"):
  476.         " helper that checks if the given cpu has sse support "
  477.         if not os.path.exists(cpuinfo):
  478.             return False
  479.         for line in open(cpuinfo):
  480.             if line.startswith("flags") and not " sse" in line:
  481.                 return False
  482.         return True
  483.  
  484.     def _usesEvmsInMounts(self):
  485.         " check if evms is used in /proc/mounts "
  486.         logging.debug("running _usesEvmsInMounts")
  487.         for line in open("/proc/mounts"):
  488.             line = line.strip()
  489.             if line == '' or line.startswith("#"):
  490.                 continue
  491.             try:
  492.                 (device, mount_point, fstype, options, a, b) = line.split()
  493.             except Exception, e:
  494.                 logging.error("can't parse line '%s'" % line)
  495.                 continue
  496.             if "evms" in device:
  497.                 logging.debug("found evms device in line '%s', skipping " % line)
  498.                 return True
  499.         return False
  500.  
  501.     def _checkAndRemoveEvms(self):
  502.         " check if evms is in use and if not, remove it "
  503.         logging.debug("running _checkAndRemoveEvms")
  504.         if self._usesEvmsInMounts():
  505.             return False
  506.         # if not in use, nuke it
  507.         for pkg in ["evms","libevms-2.5","libevms-dev",
  508.                     "evms-ncurses", "evms-ha",
  509.                     "evms-bootdebug",
  510.                     "evms-gui", "evms-cli",
  511.                     "linux-patch-evms"]:
  512.             if self.controller.cache.has_key(pkg) and self.controller.cache[pkg].isInstalled:
  513.                 self.controller.cache[pkg].markDelete()
  514.         return True
  515.  
  516.     def _addRelatimeToFstab(self):
  517.         " add the relatime option to ext2/ext3 filesystems on upgrade "
  518.         logging.debug("_addRelatime")
  519.         replaced = False
  520.         lines = []
  521.         for line in open("/etc/fstab"):
  522.             line = line.strip()
  523.             if line == '' or line.startswith("#"):
  524.                 lines.append(line)
  525.                 continue
  526.             try:
  527.                 (device, mount_point, fstype, options, a, b) = line.split()
  528.             except Exception, e:
  529.                 logging.error("can't parse line '%s'" % line)
  530.                 lines.append(line)
  531.                 continue
  532.             if (("ext2" in fstype or
  533.                  "ext3" in fstype) and 
  534.                 (not "noatime" in options) and
  535.                 (not "relatime" in options) ):
  536.                 logging.debug("adding 'relatime' to line '%s' " % line)
  537.                 line = line.replace(options,"%s,relatime" % options)
  538.                 logging.debug("replaced line is '%s' " % line)
  539.                 replaced=True
  540.             lines.append(line)
  541.         # we have converted a line
  542.         if replaced:
  543.             logging.debug("writing new /etc/fstab")
  544.             f=open("/etc/fstab.intrepid","w")
  545.             f.write("\n".join(lines))
  546.             # add final newline (see LP: #279093)
  547.             f.write("\n")
  548.             f.close()
  549.             os.rename("/etc/fstab.intrepid","/etc/fstab")
  550.         return True
  551.         
  552.  
  553.     def _rewriteFstab(self):
  554.         " convert /dev/{hd?,scd0} to /dev/cdrom for the feisty upgrade "
  555.         logging.debug("_rewriteFstab()")
  556.         replaced = 0
  557.         lines = []
  558.         # we have one cdrom to convert
  559.         for line in open("/etc/fstab"):
  560.             line = line.strip()
  561.             if line == '' or line.startswith("#"):
  562.                 lines.append(line)
  563.                 continue
  564.             try:
  565.                 (device, mount_point, fstype, options, a, b) = line.split()
  566.             except Exception, e:
  567.                 logging.error("can't parse line '%s'" % line)
  568.                 lines.append(line)
  569.                 continue
  570.             # edgy kernel has /dev/cdrom -> /dev/hd?
  571.             # feisty kernel (for a lot of chipsets) /dev/cdrom -> /dev/scd0
  572.             # this breaks static mounting (LP#86424)
  573.             #
  574.             # we convert here to /dev/cdrom only if current /dev/cdrom
  575.             # points to the device in /etc/fstab already. this ensures
  576.             # that we don't break anything or that we get it wrong
  577.             # for systems with two (or more) cdroms. this is ok, because
  578.             # we convert under the old kernel
  579.             if ("iso9660" in fstype and
  580.                 device != "/dev/cdrom" and
  581.                 os.path.exists("/dev/cdrom") and
  582.                 os.path.realpath("/dev/cdrom") == device
  583.                 ):
  584.                 logging.debug("replacing '%s' " % line)
  585.                 line = line.replace(device,"/dev/cdrom")
  586.                 logging.debug("replaced line is '%s' " % line)
  587.                 replaced += 1
  588.             lines.append(line)
  589.         # we have converted a line (otherwise we would have exited already)
  590.         if replaced > 0:
  591.             logging.debug("writing new /etc/fstab")
  592.             shutil.copy("/etc/fstab","/etc/fstab.edgy")
  593.             f=open("/etc/fstab","w")
  594.             f.write("\n".join(lines))
  595.             # add final newline (see LP: #279093)
  596.             f.write("\n")
  597.             f.close()
  598.         return True
  599.  
  600.     def _checkAdminGroup(self):
  601.         " check if the current sudo user is in the admin group "
  602.         logging.debug("_checkAdminGroup")
  603.         import grp
  604.         try:
  605.             admin_group = grp.getgrnam("admin").gr_mem
  606.         except KeyError, e:
  607.             logging.warning("System has no admin group (%s)" % e)
  608.             subprocess.call(["addgroup","--system","admin"])
  609.         # double paranoia
  610.         try:
  611.             admin_group = grp.getgrnam("admin").gr_mem
  612.         except KeyError, e:
  613.             logging.warning("adding the admin group failed (%s)" % e)
  614.             return
  615.         # if the current SUDO_USER is not in the admin group
  616.         # we add him - this is no security issue because
  617.         # the user is already root so adding him to the admin group
  618.         # does not change anything
  619.         if (os.environ.has_key("SUDO_USER") and
  620.             not os.environ["SUDO_USER"] in admin_group):
  621.             admin_user = os.environ["SUDO_USER"]
  622.             logging.info("SUDO_USER=%s is not in admin group" % admin_user)
  623.             cmd = ["usermod","-a","-G","admin",admin_user]
  624.             res = subprocess.call(cmd)
  625.             logging.debug("cmd: %s returned %i" % (cmd, res))
  626.  
  627.     def _checkVideoDriver(self, name):
  628.         " check if the given driver is in use in xorg.conf "
  629.         XORG="/etc/X11/xorg.conf"
  630.         if not os.path.exists(XORG):
  631.             return False
  632.         for line in open(XORG):
  633.             s=line.split("#")[0].strip()
  634.             # check for fglrx driver entry
  635.             if (s.lower().startswith("driver") and
  636.                 s.endswith('"%s"' % name)):
  637.                 return True
  638.         return False
  639.  
  640.     def _applyPatches(self, patchdir="./patches"):
  641.         """
  642.         helper that applies the patches in patchdir. the format is
  643.         _path_to_file.md5sum
  644.         
  645.         and it will apply the diff to that file if the md5sum
  646.         matches
  647.         """
  648.         if not os.path.exists(patchdir):
  649.             logging.debug("no patchdir")
  650.             return
  651.         if not ("PATH" in os.environ and
  652.                 [p for p in os.environ["PATH"].split(":")
  653.                  if os.path.exists(os.path.join(p,"patch"))]):
  654.             logging.debug("no binary 'patch' found in PATH")
  655.             return
  656.         for f in os.listdir(patchdir):
  657.             # skip, not a patch file, they all end with .$md5sum
  658.             if not "." in f:
  659.                 continue
  660.             logging.debug("check if patch '%s' needs to be applied" % f)
  661.             (encoded_path, md5sum) = string.split(f, ".", 1)
  662.             # FIXME: this is not clever and needs quoting support for
  663.             #        filenames with "_" in the name
  664.             path = encoded_path.replace("_","/")
  665.             if (os.path.exists(path) and
  666.                 md5(open(path).read()).hexdigest() == md5sum):
  667.                 logging.info("applying '%s'" % f)
  668.                 # dry-run first, then patch if ok
  669.                 res = call(["patch","--dry-run","-s","-p0","-i",
  670.                             patchdir+"/"+f])
  671.                 if res == 0:
  672.                     res = call(["patch","-p0","-s","-i",patchdir+"/"+f])
  673.                     logging.info("applied '%s' with %i status" % (f,res))
  674.                 else:
  675.                     logging.warning("dry run failed, ignoring patch '%s'" % f)
  676.                     
  677.     def _supportInModaliases(self, xorgdrivername, modaliasesdir="./modaliases", lspci=None):
  678.         """ 
  679.         Check if xorgdriver will work on this hardware
  680.  
  681.         This helper will check with the modaliasesdir if the given 
  682.         xorgdriver will work on this hardware (or the hardware given
  683.         via the lspci argument)
  684.         """
  685.         if not lspci:
  686.             lspci = set()
  687.             p = subprocess.Popen(["lspci","-n"],stdout=subprocess.PIPE)
  688.             for line in p.communicate()[0].split("\n"):
  689.                 if line:
  690.                     lspci.add(line.split()[2])
  691.         for filename in os.listdir(modaliasesdir):
  692.             for line in open(os.path.join(modaliasesdir,filename)):
  693.                 line = line.strip()
  694.                 if line == "" or line.startswith("#"):
  695.                     continue
  696.                 (key, pciid, xorgdriver, pkgname) = line.split()
  697.                 if xorgdriver != xorgdrivername:
  698.                     continue
  699.                 m = re.match("pci:v0000(.+)d0000(.+)sv.*", pciid)
  700.                 if m:
  701.                     matchid = "%s:%s" % (m.group(1), m.group(2))
  702.                     if matchid.lower() in lspci:
  703.                         logging.debug("found system pciid '%s' in modaliases" % matchid)
  704.                         return True
  705.         logging.debug("checking for %s support in modaliases but none found" % xorgdrivername)
  706.         return False
  707.                     
  708.  
  709.  
  710.